﻿Imports System.ComponentModel

Public Class FltrCtrl
    Private DataSource As DataView
    Private TheData As New DataView
    Private TheTable As New DataTable
    Private DefaultCol As String = ""
    Private TotalRecords As Integer = 0

#Region "Properties"

    Private _DataView As DataView
    <Browsable(True), Description("The Data View to be filtered")> _
    Public Property zDataView() As DataView
        Get
            Return _DataView
        End Get
        Set(ByVal value As DataView)
            _DataView = value
            Connect()
        End Set
    End Property


    Private _Filter As String
    <Browsable(True), DefaultValue(""), Description("The Filter String")> _
    Public Property zFilter() As String
        Get
            Return _Filter
        End Get
        Set(ByVal value As String)
            _Filter = value
        End Set
    End Property

    Private _FilterCount As Integer
    <Browsable(True), DefaultValue(0), Description("The amount of filter options being applied")> _
    Public ReadOnly Property zFilterCount() As Integer
        Get
            Return _FilterCount
        End Get
     
    End Property

    Private _RecordCount As Integer
    <Browsable(False), DefaultValue(0), Description("Record count currently filtered")> _
    Public ReadOnly Property zRecordCount() As Integer
        Get
            Return _RecordCount
        End Get

    End Property


    Private _ShowButtons As Boolean
    <Browsable(True), DefaultValue(True), Description("Show or hide the Apply and Clear buttons")> _
    Public Property zShowButtons() As Boolean
        Get
            Return _ShowButtons
        End Get
        Set(ByVal value As Boolean)
            _ShowButtons = value
            ApplyBtn.Visible = _ShowButtons
            ClearFilterBtn.Visible = _ShowButtons
        End Set
    End Property


    Private _InfoLabelOverride As String
    <Browsable(True), DefaultValue(""), Description("Overrides the Info Label")> _
    Public Property zInfolabelOverride() As String
        Get
            Return _InfoLabelOverride
        End Get
        Set(ByVal value As String)
            _InfoLabelOverride = value
        End Set
    End Property



#End Region


#Region "Functions"

    Public Event Filtered As EventHandler

    Public Event FilterCleared As EventHandler

    Private Sub Connect()
        If IsNothing(_DataView) Then

            Exit Sub
        End If

        TotalRecords = _DataView.Count

        TheData = _DataView

        _RecordCount = _DataView.Count



        UpdateInfoLabel()


        Try
            CreateTable()
            DataSource = New DataView(TheTable)


            HookFields()

            DR.DataSource = DataSource



        Catch ex As Exception

            Exit Sub
        End Try


    End Sub

    Private Sub CreateTable()

        TheTable.Clear()

        TheTable.Columns.Clear()

        TheTable.Columns.Add("AndOr", GetType(String))
        TheTable.Columns.Add("FieldName", GetType(String))
        TheTable.Columns.Add("Operator", GetType(String))
        TheTable.Columns.Add("Value", GetType(String))
        TheTable.Columns.Add("ValueDate", GetType(Date))

        _FilterCount = 0
    End Sub

    Private Sub HookFields()


        'andorbox
        AndOrBox.DataBindings.Add(New System.Windows.Forms.Binding("Text", DataSource, "AndOr", True))

        'fieldbox

        Dim col As New DataColumn

        FieldBox.Items.Clear()
        DefaultCol = ""

        For Each col In _DataView.Table.Columns
            If col.ColumnName <> "RID" Then
                If DefaultCol = "" Then
                    DefaultCol = col.ColumnName

                End If

                FieldBox.Items.Add(col.ColumnName)
            End If
            
        Next


        FieldBox.DataBindings.Add(New System.Windows.Forms.Binding("Text", DataSource, "FieldName", True))

        OperatorBox.DataBindings.Add(New System.Windows.Forms.Binding("Text", DataSource, "Operator", True))

        ValueBox.DataBindings.Add(New System.Windows.Forms.Binding("Text", DataSource, "Value", True))

        DateValueBox.DataBindings.Add(New System.Windows.Forms.Binding("Value", DataSource, "ValueDate", False))


    End Sub

    Private Sub MakeFilter()

        _Filter = ""

        If IsNothing(DataSource) Then Exit Sub

        If DataSource.Count = 0 Then Exit Sub

        Dim i As Integer


        For i = 0 To DataSource.Count - 1
            Dim TheVal As String

            If DataSource(i).Item("Operator") = "Like" Then
                TheVal = "%" & DataSource(i).Item("Value") & "%"
            Else
                TheVal = DataSource(i).Item("Value")
            End If


            If _DataView.Table.Columns(DataSource(i).Item("FieldName")).DataType Is GetType(Date) Then

                Dim TheDate As Date

                TheDate = DataSource(i).Item("ValueDate")
                TheVal = TheDate.ToShortDateString

            End If


            TheVal = TheVal.Replace("'", "''")

            If _Filter = "" Then
                _Filter = "[" & DataSource(i).Item("FieldName") & "] " & DataSource(i).Item("Operator") & " '" & TheVal & "' "

            Else
                _Filter = _Filter & DataSource(i).Item("AndOr") & " [" & DataSource(i).Item("FieldName") & "] " & DataSource(i).Item("Operator") & " '" & TheVal & "' "

            End If
        Next



    End Sub

    Public Sub AddFilterOption()
        If IsNothing(DataSource) Then Exit Sub

        ClearFilter()


        TheTable.Rows.Add("Or", DefaultCol, "=", "", Now)
        SetDateBox(DR.ItemCount - 1)
        LoadValuesBox(DR.ItemCount - 1)

        _FilterCount = TheTable.Rows.Count

    End Sub


    Private Sub SetDateBox(ByVal Itemindex As Integer)
        DR.CurrentItemIndex = Itemindex

        If IsNothing(DR.CurrentItem) Then Exit Sub

        Dim tp As FlowLayoutPanel = TryCast(DR.CurrentItem.Controls("FlowLayoutPanel2"), FlowLayoutPanel)

        If Not IsNothing(tp) Then

            Dim fbox As ComboBox
            Dim vbox As ComboBox
            Dim dbox As DateTimePicker


            fbox = TryCast(tp.Controls("FieldBox"), ComboBox)
            vbox = TryCast(tp.Controls("ValueBox"), ComboBox)
            dbox = TryCast(tp.Controls("DateValueBox"), DateTimePicker)

            If Not IsNothing(fbox) Then
                If _DataView.Table.Columns(fbox.Text).DataType Is GetType(Date) Then

                    dbox.Visible = True
                    vbox.Visible = False


                Else
                    dbox.Visible = False
                    vbox.Visible = True
                End If
            End If

        End If

    End Sub

    Private Sub LoadValuesBox(ByVal Itemindex As Integer)
        'load the value box with values

        DR.CurrentItemIndex = Itemindex

        If IsNothing(DR.CurrentItem) Then Exit Sub


        Dim tp As FlowLayoutPanel = TryCast(DR.CurrentItem.Controls("FlowLayoutPanel2"), FlowLayoutPanel)

        If Not IsNothing(tp) Then

            Dim valbox As ComboBox
            Dim fbox As ComboBox

            valbox = TryCast(tp.Controls("ValueBox"), ComboBox)
            fbox = TryCast(tp.Controls("FieldBox"), ComboBox)

            If Not IsNothing(valbox) Then
                'valbox.Text = ""
                valbox.Items.Clear()

                Dim rec As DataRowView

                Dim valitems As New List(Of String)

                For Each rec In TheData


                    Dim i As Integer = 0
                    Dim cval As String = ""


                    If IsDBNull(rec(fbox.Text)) Then
                        cval = ""
                    Else
                        cval = rec(fbox.Text)
                    End If

                    valitems.Add(cval)

                    ' If addme Then valbox.Items.Add(cval)
                Next

                valitems = valitems.Distinct().ToList()

                valbox.Items.AddRange(valitems.ToArray)

                Dim obox As ComboBox

                obox = TryCast(tp.Controls("OperatorBox"), ComboBox)

                Dim oldop As String = "="

                If Not IsNothing(obox) Then
                    oldop = obox.Text

                    If _DataView.Table.Columns(fbox.Text).DataType Is GetType(String) Then
                        'it should only have = <> and Like... we cant clear and add

                        Select Case oldop
                            Case "<", ">", "<=", ">="
                                oldop = "="
                        End Select

                        obox.Text = "="

                        'remove all

                        obox.Items.Remove("<")
                        obox.Items.Remove(">")
                        obox.Items.Remove("<=")
                        obox.Items.Remove(">=")
                        obox.Items.Remove("<>")
                        '   obox.Items.Remove("=")
                        obox.Items.Remove("Like")

                        ' obox.Items.Add("=")
                        obox.Items.Add("<>")
                        obox.Items.Add("Like")

                    Else
                        If oldop = "Like" Then
                            oldop = "="
                        End If

                        obox.Text = "="

                        'remove all 

                        obox.Items.Remove("<")
                        obox.Items.Remove(">")
                        obox.Items.Remove("<=")
                        obox.Items.Remove(">=")
                        obox.Items.Remove("<>")
                        obox.Items.Remove("Like")

                        obox.Items.Add("<")
                        obox.Items.Add(">")
                        obox.Items.Add("<=")
                        obox.Items.Add(">=")
                        obox.Items.Add("<>")
                    End If


                    obox.Text = oldop

                    If obox.Text = "" Then obox.Text = "="


                End If


            End If
        End If
    End Sub
#End Region

    Public Sub ClearFilter()
        _Filter = ""
        _DataView.RowFilter = ""

        _RecordCount = _DataView.Count

        UpdateInfoLabel()

        RaiseEvent FilterCleared(Me, EventArgs.Empty)

    End Sub

    Private Sub ClearFilterBtn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ClearFilterBtn.Click
        ClearFilter()

    End Sub

    Public Sub ApplyFilter()
        If IsNothing(_DataView) Then Exit Sub

        MakeFilter()

        Try
            _DataView.RowFilter = _Filter
            _RecordCount = _DataView.Count

        Catch ex As Exception
            'filter is dodge... so ignore
        End Try


        UpdateInfoLabel()

        RaiseEvent Filtered(Me, EventArgs.Empty)

    End Sub

    Private Sub ApplyBtn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ApplyBtn.Click
        ApplyFilter()

    End Sub

    Private Sub UpdateInfoLabel()

        If _InfoLabelOverride = "" Then
            _RecordCount = _DataView.Count
            InfoLabel.Text = "Showing " & _RecordCount.ToString & " out of " & TotalRecords.ToString & " records"
        Else
            InfoLabel.Text = _InfoLabelOverride
        End If



    End Sub

    Private Sub RemoveFilterBtn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RemoveFilterBtn.Click
        ClearFilter()

        DataSource.Item(DR.CurrentItemIndex).Delete()

        _FilterCount = TheTable.Rows.Count

    End Sub



    Private Sub Addbtn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Addbtn.Click
        AddFilterOption()

    End Sub


    Private Sub DR_DrawItem(ByVal sender As System.Object, ByVal e As Microsoft.VisualBasic.PowerPacks.DataRepeaterItemEventArgs) Handles DR.DrawItem
        'dont draw the andor box if it is the first item

        Dim tp As FlowLayoutPanel = TryCast(e.DataRepeaterItem.Controls("FlowLayoutPanel2"), FlowLayoutPanel)

        If Not IsNothing(tp) Then


            Dim abox As ComboBox = tp.Controls("AndOrBox")

            If e.DataRepeaterItem.ItemIndex = 0 Then
                abox.Visible = False

            Else
                abox.Visible = True

            End If
        End If
    End Sub

    Private Sub FieldBox_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles FieldBox.SelectedIndexChanged
        SetDateBox(DR.CurrentItemIndex)

        LoadValuesBox(DR.CurrentItemIndex)
    End Sub

    Private Sub PasteClipboard()


        Dim s As String
        Dim value As Object

        Dim AndOr As String
        Dim TheCol As String
        Dim Sign As String

        If TheTable.Rows.Count <= 0 Then Exit Sub

        Dim r As DataRow

        r = TheTable.Rows(TheTable.Rows.Count - 1)

        AndOr = "Or"
        TheCol = r("FieldName")
        Sign = r("Operator")

        Try



            s = Clipboard.GetText()
            Dim i, ii As Integer


            Dim tArr() As String = s.Split(ControlChars.NewLine)
            Dim arT() As String


            For i = 0 To tArr.Length - 1
                If tArr(i) <> "" Then
                    arT = tArr(i).Split(vbTab)

                    For ii = 0 To arT.Length - 1

                        value = arT(ii).TrimStart

                        'add it
                        If IsNothing(DataSource) Then Exit Sub

                        ClearFilter()

                        If value.ToString <> "" Then
                            If i = 0 Then
                                r("Value") = value.ToString
                            Else
                                TheTable.Rows.Add(AndOr, TheCol, Sign, value.ToString, Now)
                            End If
                        End If


                        SetDateBox(DR.ItemCount - 1)
                        'LoadValuesBox(DR.ItemCount - 1)

                        _FilterCount = TheTable.Rows.Count

                    Next

                End If


            Next


        Catch ex As Exception
            MsgBox("There was an error pasting the values:  " & ex.Message)
        End Try
    End Sub


    Private Sub PasteButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles PasteButton.Click
        PasteClipboard()

    End Sub

    Private Sub RemoveAllBtn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RemoveAllBtn.Click
        ClearFilter()

        While DataSource.Count > 0
            DataSource.Item(0).Delete()
        End While


        _FilterCount = TheTable.Rows.Count
    End Sub
End Class
